/**
 * fileName: YLES_Tool
 * @NApiVersion 2.1
 */
import log = require("N/log");
import record = require("N/record");
import runtime = require("N/runtime");
import search = require("N/search");
import format = require("N/format");
import file = require("N/file");

import {CustomRecordType} from "./YLES_RELATED_RECORDTYPE";
import {FieldValue} from "N/record";
import {ExpressionType} from "N/workbook";
// @ts-ignore
import * as Papa from "./papaparse";
import {EntryPoints} from "N/types";
import {getAllItem, getCsvFolder, ObjectJson} from "./YLES_SEARCH_TOOL";


//加法函数，用来得到精确的加法结果
//说明：javascript的加法结果会有误差，在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
//调用：accAdd(arg1,arg2)
//返回值：arg1加上arg2的精确结果
export function accAdd(arg1: number | string, arg2: number | string | undefined) {
    if (!arg2) {
        arg2 = 0;
    }
    if (!arg1) {
        arg1 = 0;
    }
    arg1 = +arg1;
    arg2 = +arg2;
    var r1, r2, m, c;
    try {
        r1 = arg1.toString().split(".")[1].length
    } catch (e) {
        r1 = 0
    }
    try {
        r2 = arg2.toString().split(".")[1].length
    } catch (e) {
        r2 = 0
    }
    c = Math.abs(r1 - r2);
    m = Math.pow(10, Math.max(r1, r2))
    if (c > 0) {
        var cm = Math.pow(10, c);
        if (r1 > r2) {
            arg1 = parseFloat(arg1.toString().replace(".", ""));
            arg2 = parseFloat(arg2.toString().replace(".", "")) * cm;
        } else {
            arg1 = parseFloat(arg1.toString().replace(".", "")) * cm;
            arg2 = parseFloat(arg2.toString().replace(".", ""));
        }
    } else {
        arg1 = parseFloat(arg1.toString().replace(".", ""));
        arg2 = parseFloat(arg2.toString().replace(".", ""));
    }
    return (arg1 + arg2) / m
}


//减法函数，用来得到精确的减法结果
export function Subtr(arg1:number, arg2:number) {
    if(!arg1){
        arg1 = 0;
    }
    if(!arg2){
        arg2 = 0;
    }
    var r1, r2, m, n;
    try { r1 = arg1.toString().split(".")[1].length } catch (e) { r1 = 0 }
    try { r2 = arg2.toString().split(".")[1].length } catch (e) { r2 = 0 }
    m = Math.pow(10, Math.max(r1, r2));
    //last modify by deeka
    //动态控制精度长度
    n = (r1 >= r2) ? r1 : r2;
    return +((arg1 * m - arg2 * m) / m).toFixed(n);
}

//乘法函数，用来得到精确的乘法结果
//说明：javascript的乘法结果会有误差，在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
//调用：accMul(arg1,arg2)
//返回值：arg1乘以arg2的精确结果
export function accMul(arg1: number | string, arg2: number | string | undefined) {
    if (!arg1 || !arg2) {
        return 0;
    }
    arg1 = +arg1;
    arg2 = +arg2;

    var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
    try {
        m += s1.split(".")[1].length
    } catch (e) {
    }
    try {
        m += s2.split(".")[1].length
    } catch (e) {
    }
    return parseFloat(s1.replace(".", "")) * parseFloat(s2.replace(".", "")) / Math.pow(10, m)
}


//除法函数，用来得到精确的除法结果
//说明：javascript的除法结果会有误差，在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
//调用：accDiv(arg1,arg2)
//返回值：arg1除以arg2的精确结果
export function accDiv(arg1:number, arg2:number) {
    if(!arg1 || !arg2){
        return 0;
    }
    var t1 = 0, t2 = 0, r1, r2;
    try {
        t1 = arg1.toString().split(".")[1].length
    } catch (e) {
    }
    try {
        t2 = arg2.toString().split(".")[1].length
    } catch (e) {
    }
    r1 = parseFloat(arg1.toString().replace(".", ""))
    r2 = parseFloat(arg2.toString().replace(".", ""))
    return (r1 / r2) * Math.pow(10, t2 - t1);
}

//判断是真是假
export function trueOrFalse(val: FieldValue): boolean {
    if (val) {
        if (val === 'T' || val === true) {
            return true;
        }
    }
    return false;
}

export function submitLogField(val: { id: number | string, values: object }) {
    //@ts-ignore
    record.submitFields({type: CustomRecordType().DOSAGE_MRP_LOG as string, ...val});
}

//获取脚本传递的参数
export function getScriptParams(name: string) {
    return runtime.getCurrentScript().getParameter({name: name});
}

/**
 * 依据脚本英文ID，找到对应的脚本内部标识（数字ID）
 * @params id - 脚本英文ID全称
 * @return integer - 对应的脚本内部标识（数字ID）
 */
export function searchScriptById(id: string) {
    var script = '';
    if (id) {
        search.create({
            type: 'script', filters: [
                ['scriptid', 'is', id]
            ]
        }).run().each(function (res) {
            script = res.id;
            return false;
        });
    }
    if (!script) throw 'there is no matched script by ' + id;
    log.debug('script', script);
    return script;
}

//依据部署ID查找对应的脚本部署ID，若不存在则新建
export function getCreateScriptDeployment(obj: { scriptId: string, depId: string }) {
    const Search = search.create({
        type: 'scriptdeployment',
        filters: [['script.scriptid', 'is', obj.scriptId], 'and', ['scriptid', 'is', obj.depId]],
        columns: [{name: 'internalid'}]
    });
    const data = Search.run().getRange({start: 0, end: 1});
    if (data.length === 0) {
        //若不存在此脚本部署，则新建
        const spId = searchScriptById(obj.scriptId);
        const rec = record.create({
            type: 'scriptdeployment',
            defaultValues: {'script': spId}
        });
        rec.setValue('scriptid', obj.depId.replace('customdeploy', ''));
        rec.save();
    }
}


//将str转为日期
export function stringToDate(str: string, type?: string) {
    if (str) {
        if (type == 'YYYY/MM/DD' || type == 'MM/DD/YYYY') {
            return new Date(str);
        } else {
            if (typeof format.parse({value: str, type: 'date'}) == 'object') {
                return format.parse({value: str, type: 'date'}) as Date;
            }
        }
    }
    return '';
}

//日期转为字符串
export function dateToString(date: Date, type?: string) {
    if (!date) return '';
    if (type == 'MM/DD/YYYY') {
        return addZero(date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear();
    } else if (type == 'YYYY/MM/DD') {
        return date.getFullYear() + '/' + addZero(date.getMonth() + 1) + '/' + date.getDate();
    } else {
        return format.format({value: date, type: 'date'});
    }
}

function addZero(n: number) {
    return n > 9 ? n : ('0' + n);
}

//将csv数据转为json
export function parseCsv(csvFile: file.File) {
    const ret : {[prop: string]: {}[]} = {};
    let index = 1;
    //循环CSV数组
    const iterator = csvFile.lines.iterator();
    //Skip the first line (CSV header)
    iterator.each(function () {return false;});
    iterator.each(function (line:{value:string}) {
        let errors = [];
        const lineValues = line.value.split(',');
        // log.debug('lineValues',lineValues);
        const item = (lineValues[0] || '').trim();
        const barcode = (lineValues[1] || '').trim();

        ret[item] = ret[item] || [];
        ret[item].push({
            barcode: barcode,
            line: index
        });

        index++;
        return true;
    });
    return ret;
}

//获取MapReduce脚本的报错信息
export function getMRErrorStr(cxt:EntryPoints.MapReduce.summarizeContext) {
    let erStr = '';
    //INPUTDATA ERROR
    if (cxt.inputSummary.error) {
        erStr += cxt.inputSummary.error + ';\n';
    }
    //MAP ERROR
    cxt.mapSummary.errors.iterator().each(function (key, error, executionNo) {
        const mapEr = JSON.parse(error);
        erStr += mapEr.message + ';\n';
        return true;
    });
    //REDUCE ERROR
    cxt.reduceSummary.errors.iterator().each(function (key, error, executionNo) {
        const reduceEr = JSON.parse(error);
        erStr += reduceEr.message + ';\n';
        return true;
    });
    return erStr;
}


//将百分比去除，返回数字
export function percentToString(percent:string) {
    if (percent) return String(percent).replace('%','');
    return percent;
}


/**
 * 将数字转为千分位显示
 * @param number            数值
 * @param decimals          保留小数位
 * @param decPoint         小数点符号
 * @param thousandsSep     千分位符号
 * @return {number}
 */
export function formatNumberAsThousand(number:number | string, decimals: number, decPoint?: string, thousandsSep?: string) {
    number = (number + '').replace(/[^0-9+-Ee.]/g, '');
    var n = !isFinite(+number) ? 0 : +number,
        prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
        sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep,
        dec = (typeof decPoint === 'undefined') ? '.' : decPoint,
        s: string| string[] = '',
        toFixedFix = function(n:number, prec:number) {
            var k = Math.pow(10, prec);
            return '' + Math.floor(n * k) / k;
        };
    s = (prec ? toFixedFix(n, prec) : '' + Math.floor(n)).split('.');
    var re = /(-?\d+)(\d{3})/;

    while(re.test(s[0])) {
        s[0] = s[0].replace(re, "$1" + sep + "$2");
    }
    if((s[1] || '').length < prec) {
        s[1] = s[1] || '';
        s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
}

//千分位转化为数字
export function toNumber(str: string | number) {
    if (str) {
        str = String(str).replace(/,/g,'');
        return parseFloat(str);
    }
    return 0;
}

//数组切片
export function arrChunk(arr:[],size:number){
    if(arr.length === 0){
        return [];
    }
    const tempArr = [];
    const len = Math.ceil(arr.length / size);
    let last = 0;
    for(let i = 0;i < len;i++){
        if(size * i >= arr.length){
            last = arr.length;
        }else{
            last = size * i + size;
        }
        tempArr.push(arr.slice(size * i,last));
    }
    return tempArr;
}


//校验导入的CSV数据
export function validateData(csvFile: file.File,rid?:string | number) {
    //获取所有的Item信息
    const itemInfo = getAllItem();
    const csvBarcode: string[] = [];

    const folderId = getCsvFolder() as number;
    //创建校验成功的CSV数据文件
    const ckSuccessCsv = file.create({
        fileType: file.Type.CSV,
        name: 'checkSuccessCsv_' + new Date().getTime(),
        folder: folderId
    });
    ckSuccessCsv.encoding = 'GB18030';//file.Encoding.GB18030;//UTF_8
    ckSuccessCsv.appendLine({
        value: 'itemId,barcode'
    })

    //创建校验错误的CSV文件
    const ckErrorCsv = file.create({
        fileType: file.Type.CSV,
        name: 'checkErrorCsv_' + new Date().getTime(),
        folder: folderId
    });
    ckErrorCsv.encoding = 'GB18030';//file.Encoding.GB18030;//UTF_8
    ckErrorCsv.appendLine({
        value: 'itemId,barcode,原行号,错误提示'
    });
    const sd = (new Date).getTime();
    //是否全部通过校验
    let validatePass = true;
    //是否存在正确的明细行
    let hasSuccessLine = 0;
    //循环CSV数组
    const iterator = csvFile.lines.iterator();
    //Skip the first line (CSV header)
    iterator.each(function () {return false;});
    iterator.each(function (line:{value:string}) {
        let errors = [];
        const lineValues = line.value.split(',');
        // log.debug('lineValues',lineValues);
        const item = (lineValues[0] || '').trim();
        const barcode = (lineValues[1] || '').trim();
        const bcAr = barcode.replace(item,'').split('-');

        /**
         * ①：校验item
         * 字段的值为货品的itemid字段值，需要校验货品ID在系统内是否存在
         */
        if (!item || !itemInfo.includes(item)) {
            errors.push(`货品ID不存在;`);
            validatePass = false;
        }
        /**
         * ②：校验barcode
         * 【条码】的格式校验：【条码】组成规则为 货品ID-YYYYMMDD-99999999。需要校验CSV内提供的条码是否符合组成规则。具体说明如下：
         * 【货品ID】部分需要与CSV文件当前行的第一个字段的值保持一致，【YYYYMMDD】部分为8位年月日，【99999999】部分为8位随机数字
         */
        if (barcode.indexOf(item) != 0) {
            //是否以itemid开头
            errors.push(`条码不符合规则;`);
            validatePass = false;
        }else if (!/^(\d{8})$/.test(bcAr[2])) {
            //结束是否是8位流水号
            errors.push(`条码不符合规则;`);
            validatePass = false;
        }else {
            if (!/^(\d{4})(\d{2})(\d{2})$/.test(bcAr[1])) {
                //中间是否是 YYYYMMDD
                errors.push(`条码不符合规则;`);
                validatePass = false;
            }else {
                //中间是否是有效日期
                // @ts-ignore
                if (new Date(bcAr[1].substr(0,4) + '/' + bcAr[1].substr(4,2) + '/' + bcAr[1].substr(6,2)) == 'Invalid Date') {
                    errors.push(`条码不符合规则;`);
                    validatePass = false;
                }
            }

        }

        /**
         * ③： 校验重复
         * CSV文件内，货品ID+条码维度，是否有重复
         */
        if (csvBarcode.includes(barcode)) {
            errors.push(`本条数据与原文件内第${csvBarcode.indexOf(barcode) + 1}行重复;`);
            validatePass = false;
        }

        csvBarcode.push(barcode);
        //将校验失败的数据存储在错误文件中
        if (errors.length > 0) {
            ckErrorCsv.appendLine({
                value: `${item},${barcode},${csvBarcode.length},${errors.toString().replace(/,/g,'').replace(/;$/,"")}`
            });
        }else {
            ckSuccessCsv.appendLine({
                value: `${item},${barcode}`
            });
            hasSuccessLine++;
        }


        //若传入日志记录，则输出session
        if (rid) {
            if (csvBarcode.length % 10000 == 0) {
                setImpLogCheckedLine(rid,csvBarcode.length);
                log.debug({title:'已校验',details:csvBarcode.length +'条数据'});
            }
        }

        return true;
    });
    if (rid) setImpLogCheckedLine(rid,csvBarcode.length);
    const ed1 = (new Date).getTime();
    log.debug({title:'处理数据耗费的时间',details:ed1 - sd});

    let ckErrorId: string | number = '';
    let ckSuccessCsvId: string | number = '';
    if (!validatePass) {
        ckErrorId = ckErrorCsv.save();
        log.debug({title:'成功创建校验失败CSV文件ID:',details:ckErrorId});
    }

    const ed2 = (new Date).getTime();
    log.debug({title:'保存ckErrorCsv的时间',details:ed2 - ed1});

    if (hasSuccessLine > 0) {
        ckSuccessCsvId = ckSuccessCsv.save();
        log.debug({title:'成功创建校验成功CSV文件ID',details:ckSuccessCsvId});
    }

    const ed3 = (new Date).getTime();
    log.debug({title:'保存ckSuccessCsv的时间',details:ed3 - ed2});

    return {pass: validatePass, status: '',ckErrorId,ckSuccessCsvId,successLine:hasSuccessLine};
}


//使用papaparse校验数据
export function PapaValidateData(csvFile: file.File,rid?:string | number) {
    const paData = Papa.parse(csvFile.url,{header: true, skipEmptyLines: 'greedy',fastMode: true});
    log.debug({title:'paData',details:paData});
    const data = paData.data;
    log.debug({title:'data',details:data});
    data.map(function (d: { [x: string]: any }, index: any) {
        log.debug({title:'data detail',details:d});

    })

    const rt: any = {};
    return rt;
}

//设置已校验的行数
function setImpLogCheckedLine(rid:string | number,num:number) {
    record.submitFields({
        type: CustomRecordType().IMPORT_ITEM_BARCODE_LOG,
        id: rid,
        values: {
            custrecord_yles_ckd_line_no: num.toString()
        }
    });
}

//更新导入日志
export function changeImportLog(validateRes: any, importLog: string) {
    let values: ObjectJson = {};
    if (validateRes.pass == false) {
        values.custrecord_yles_status = '4'; //校验出错
        values.custrecord_yles_ck_error_csv = validateRes.ckErrorId;
        values.custrecord_yles_imp_success_csv = validateRes.ckSuccessCsvId;
        values.custrecord_yles_imp_csv_line_no = validateRes.successLine;
        values.custrecord_yles_end_time = new Date();
    }else {
        values.custrecord_yles_status = '7'; //校验成功
        values.custrecord_yles_ck_error_csv = '';
        values.custrecord_yles_imp_success_csv = validateRes.ckSuccessCsvId;
        values.custrecord_yles_imp_csv_line_no = validateRes.successLine;
    }
    record.submitFields({type: CustomRecordType().IMPORT_ITEM_BARCODE_LOG, id: importLog, values: values});
}
